Game Format Plugins
===================

To add a new format, first choose an appropriate `prefix` (like "pgmmv") and create "prefix.c", where you include "../main.h" and
add this at the bottom:
```c
ENGINE_MODULE(prefix, "name of the format string")
```
For an example, see [pgmmv.c](pgmmv.c), it also has lots of comments.

Functions to be Implemented
---------------------------

To avoid name space conflicts, in general it is a good practice to define all your variables and local functions as `static` (that
won't make them actually static, it just tells the compiler that they won't be visible outside of your source file). However
never use static on the following functions (they must be accessible from the main program, hence the mandatory unique prefix):

```c
int prefix_detect(char *path, uint8_t *buf, uint64_t size);
```
Receives the folder or file name. If it is a folder then `buf` is NULL and `size` is 0, otherwise `size` is the total length of
the file, and `buf` contains *the first 4096 bytes* of the contents, for magic bytes detection (not the entire file!). Return 1
if format detected, 0 if not.

```c
void prefix_load(char *path, in isdir);
```
Load and parse the folder or file. Call various GR API (see section "Functions to Use" below) to add animations, maps, etc. to
the viewer. This function *MUST NOT* make any changes to game files. If `engine_keylen` is greater than zero, then use what's
given in `engine_key[]` and do not try to autodetect the encryption key. Also set the game's title to `engine_game[]` and
`engine_features` bit flags depending on what you've found. The `EF_DECRYPT` feature is for unpacking raw assets too (because those
are commonly encrypted as well), and makes the "Decrypt / Unpack all" button to appear on the "Info" tab. Other features make more
tabs available to the user interface (eg. setting `EF_SPRITES` will make the "Sprites" tab to appear).

```c
void prefix_unload(void);
```
Free resources if directly allocated by `prefix_load()`, no need to free GR API allocated stuff.

```c
void prefix_decrypt(char *path, in isdir);
```
Decrypt / unpack file or all files in a directory (use `find()`, that will recursively walk the directory-tree and call a callback
on each and every file). If `engine_keylen` is greater than zero, then use what's given in `engine_key[]` and do not try to autodetect
the encryption key.

```c
void prefix_drawmap(map_t *map);
```
Draw `map` to the off-screen pixel buffer. Should call `map_tile()` for that. Map has `map.tid` a custom tile set id, `map.tw` tile
width in pixels, `map.th` tile height in pixels, `map.w` vertical number of tiles, `map.h` horizontal number of tiles, `map.l` number
of layers, and `map.data[]` an array of `map.w` x `map.h` x `map.l` engine specific tile ids.

```c
void prefix_translate(char *path);
```
Take `texts[]` with `numcol` columns and `numrow` rows, where the first row is the language code and others have a `texts[].id`
and `texts[].value[]` fields, and update the game files with those texts.

Functions to Use
----------------

These you call to get data and to add decoded assets to the viewer.

### User Feedback

```c
void debug(char *fmt, ...);
```
Prints a debug message to the log file and to the console. Only works if GAME RIPPER was started with the `-v` verbose flag,
otherwise does nothing.

```c
void status(int msg, uint64_t cur, uint64_t tot);
```
Displays the C= 64 loading effect and a progress bar. `msg` is a define specified in [src/etc/texts.csv](../etc/texts.csv) and
refers to a translated message.

```c
void msgbox(int error, int msg, char *param);
```
Displays an OS-independent (info if `error` is 0) message box modal with a translated `msg` message and an optional `param`
parameter (can be NULL). Try to avoid using this, *DO NOT* bother the user with a pop-up message that stops procssing the game
files. Use `debug()` instead and a flag, only show one error pop-up at the very end if that flag is set.

### File Operations

```c
int fileknown(uint8_t *buf);
```
Returns 1 if file magic recognized. `buf` must be at least 32 bytes long.

```c
int fileasset(int id, char *name, uint8_t *buf, uint64_t size);
```
A common dispatcher to add any kind of known assets to the appropriate list. Returns 0 if buffer can be freed and 1 if asset was
added and buffer is still in use.

```c
void filemkdir(char *fn);
```
Creates a directory. `fn` might contain `/` directory separator on Windows too, and UTF-8 encoded UNICODE characters in the
name are handled properly as well. No need to worry about Japanese file names on English Windows anymore.

```c
void *fileopen(char *fn, uint64_t *size);
```
Open a file for reading. `fn` might contain `/` directory separator on Windows and UTF-8 encoded UNICODE characters. If file
is successfully opened, `size` is set to its size, and a non-NULL OS-independent handle is returned, to be used with the
`fileread()` / `filewrite()` / `fileseek()` / `fileclose()` functions (see below).

```c
void *fileopen(char *fn, NULL);
```
Open an empty file for writing if `size` is NULL. Creates the file if it doesn't exists yet, otherwise deletes it first.

```c
uint64_t fileread(void *f, void *buf, uint64_t size);
```
Read from opened file. Properly handles bigger than 4G files on Windows too.

```c
uint64_t filewrite(void *f, void *buf, uint64_t size);
```
Write to opened file.

```c
void fileseek(void *f, uint64_t offs);
```
Seek in an opened file from the beginning.

```c
void fileclose(void *f);
```
Close an opened file.

```c
int fileexists(char *fn);
```
Returns 1 if `fn` exists and is a regular file, 0 if the file doesn't exists or if it's a directory.

```c
uint8_t* getfile(char *fn, uint64_t *size);
```
Reads a file entirely into memory. Sets its size in `size` and returns the contents in a newly malloc'd buffer. It is the
caller's responsibility to call `free()` on that buffer when finished processing. On error (if file not found or it is too
large to fit in memory), sets `size` to 0 and returns NULL.

```c
int putfile(char *fn, uint8_t *buf1, uint64_t size1, uint8_t *buf2, uint64_t size2, uint8_t *buf3, uint64_t size3);
```
Writes out three memory buffers into a newly created file. It uses three buffers because it's common that you have to
modify in the middle, so you have a first unmodified buffer, a second modified buffer and a third unmodified buffer to
write. The second `buf2`, `size2` and third `buf3`, `size3` buffer arguments can be NULL and 0.

```c
typedef int (*filecb_t)(char *fn);
int find(char *path, int subdirs, filecb_t filecb);
```
If `path` is a file, then it calls the `filecb` callback on it. Otherwise it iterates on the directory entries and calls
the `filecb` on each and every file within that directory. If `subdirs` is not 0, then it recursively descends into all
sub-directories as well. If the `filecb` callback returns 0 then it stops.

```c
uint64_t du(char *path);
```
Returns disk usage, recursively iterates on a directory-tree and gives the total sum of all the file contents within.

```c
void opendialog(int msg, int dir);
```
Opens an OS-specific file or folder chooser, and only allows to select already existing entries (except when `msg` is
`SAVEDIR`, then "New Folder" button will also appear). The provided path is returned in the global `fn[]` string, which
is zeroed out if user pressed "Cancel".

```c
void savedialog(char *path, char *name, uint8_t *buf, uint64_t size);
```
Opens an OS-specific file chooser, and if the user presses "Save", saves the buffer into it. The filename `name` is
mandatory, the `path` can be NULL.

### Sprites

Both sprite sheets and individual sprites might be referenced by a numeric id or by a name, or you could just supply
these as -1, NULL and use the internal index instead. Depends on the game engine which method you prefer.

```c
int sprites_detect(uint8_t *buf);
```
Returns 1 if `buf` contains an image asset. `buf` must be at least 32 bytes long.

```c
uint32_t *sprites_decode(uint8_t *buf, uint64_t size, int *w, int *h);
```
Decode an image asset in any of the known formats. Returns NULL on error, otherwise a newly allocated pixel buffer and
dimensions in `w` and `h`. For completeness only, use `sprites_addsheet()` instead.

```c
uint8_t *sprites_encode(int sprite, uint64_t *size);
```
Encode the `sprite` with that internal index into an image asset, either PNG (with 1 frame) or animated GIF (if it has multiple
frames). Returns NULL on error, otherwise a newly allocated byte buffer and its size in `size`. You probably won't need this.

```c
int sprites_addsheet(int id, char *name, uint8_t *buf, uint32_t size);
```
Adds a new sprite sheet from an image asset. If `name` is given, then it must be unique, so a previously created sheet is returned
if exists. Same with the numeric `id`. If `id` is -1 and `name` is NULL, then a new sprite sheet is always added. If `buf` is NULL
and either `id` isn't -1 or `name` isn't NULL, then it looks up sprite sheet. Returns internal sprite sheet index or -1 on error.

```c
int sprites_newsheet(int id, char *name, int w, int h);
```
Add a new empty sprite sheet. You probably won't need this, just for completeness.

```c
int sprites_add(int id, char *name, int w, int h, int dx, int dy, int sheet, int sx, int sy, int sw, int sh, int dur, int sfx);
```
Adds a new sprite or sprite animation frame. If `name` is given, then it must be unique, so a previously created sprite is
used if exists. If `id` is -1 and `name` is NULL, or the sprite not found, then a new sprite is created with `w` and `h` overall
dimensions. One frame is taken from a sprite sheet (with internal index `sheet` at `sx` and `sy` of `sw` x `sh` size) and displayed
at `dx` and `dy` on the sprite for `dur` milliseconds, and if `sfx` is not -1, then an internal sound effect index to be played
along with the frame. Returns the internal sprite index or -1 on error.

```c
void sprites_draw(int sprite, int frame, uint32_t *buf, int w, int h, int p, int x, int y, int scale);
```
Draws a sprite's frame (or its thumbnail if `frame` is -1) to a pixel buffer. You probably won't need this.

### Maps

```c
int map_add(int id, char *name, int tid, int tw, int th, int w, int h, int l);
```
Adds a new map. If `name` is given, then it must be unique, so a previously created map is used if exists. If `id` is -1 and `name`
is NULL, or the map not found, then a new map is created with `w` and `h` overall dimensions in tiles and `l` layers, and tile size
is set to `tw` x `th` and tile set to `tid`. Returns the internal map index or -1 on error. The map data by default is filled with
tile -1 (nothing). Use `map_data()` to get a pointer and then you can set the tile indeces to be drawn on the map.

```c
int *map_add_under(int map);
```
Adds a new map layer under the existing layers. If `map` not found or layer cannot be allocated, returns NULL. Otherwise returns
a pointer to the newly allocated map layer, which is filled with tile -1 (nothing) by default.

```c
int *map_add_above(int map);
```
Adds a new map layer above the existing layers. If `map` not found or layer cannot be allocated, returns NULL. Otherwise returns
a pointer to the newly allocated map layer, which is filled with tile -1 (nothing) by default.

```c
int *map_data(int map, int l);
```
Returns a pointer to the `map`'s `l`th layer data, which contains `w` x `h` tile numbers. The 0th layer is below the others, and
(number of layers - 1)th is on top. On error (no such map or layer) returns NULL.

```c
int map_sprite(int map, int sprite, int x, int y);
```
Add a `sprite` to be displayed on the `map`. The sprite will be centered top at `x`, `y`.

```c
void map_tile(int sheet, int x, int y, int w, int h, int dx, int dy);
```
Copies `w` x `h` pixels from `sheet` (internal sheet index, returned by `sprite_addsheet()`) at `x`, `y` position to the off-screen
pixel buffer's `dx`, `dy` position. The `prefix_drawmap()` function should call this to render tiles.

### Audio

```c
int audio_detect(uint8_t *buf);
```
Returns 1 if `buf` contains an audio asset. `buf` must be at least 32 bytes long.

```c
uint8_t *audio_decode(uint8_t *buf, uint64_t size, int *len);
```
Decode an audio asset in any of the known formats. Returns NULL on error, otherwise a newly allocated PCM buffer and
length in `len`. For completeness only, use `audio_addsfx()` or `audio_addbgm()` instead.

```c
int audio_addsfx(int id, char *name, uint8_t *buf, uint32_t size);
```
Adds a new sound effect from an audio asset. If `name` is given, then it must be unique, so a previously created sheet is
returned if exists. Same with the numeric `id`. If `id` is -1 and `name` is NULL, then a new sound effect is always added.
Returns internal sound effect index or -1 on error.

```c
int audio_addbgm(int id, char *name, uint8_t *buf, uint32_t size);
```
Same as above, but for background music.

### Translations

```c
int texts_addrow(int id);
```
Adds a new row to the texts table. `id` is game specific, could be anything non-zero, but must be unique (you can keep an
array of which game files and at which position contain the string and index it with this id for example).

```c
int texts_getcol(char *str);
```
Looks up which column stores a specific language. `str` is a 5 character long locale, eg. "en_US" or "ja_JP".
If the language code is not found, then a new column is added (up to 128 columns).

```c
texts[numrow].id;            /* the game specific id of the text */
texts[numrow].value[numcol]; /* translated text, zero terminated UTF-8 */
```
You can access all translated texts in a simple struct array. There are `numcol` languages and `numrow` - 1 texts (first row
has zero `id` and its value stores the language codes).

```c
int base64_decode(char *s, uint8_t *out, int len);
```
BASE64 decode a string in place.

```c
uint64_t gethex(char *str, int num);
```
Convert a string with hexadecimal numbers into integer.

```c
char *getvalue(char *json, int *value)
```
Reads an integer from a JSON formated string with decimal numbers. Returns new JSON position.

```c
char *getstr(char *json, char *str, int maxlen);
```
Reads an unquoted string from an JSON formated string. Returns new JSON position.

```c
char *newstr(char **jsonptr);
```
Same as `getstr()`, but allocates buffer for the new unquoted string. Returns new buffer and adjusts `*jsonptr`.

```c
char *shiftjis2utf8(char *json, char *str, int maxlen);
```
Same as `getstr()`, but converts from SHIFTJIS (CP932) to UTF-8. Returns new JSON position.

```c
char *toutf8(char *str, uint32_t u);
```
Writes `u` UNICODE to string as UTF-8, returns new string position.

```c
int validutf8(char *str);
```
Returns 1 if `str` is a valid zero terminated UTF-8 string.

### Cryptography

```c
int twofishInit(TwofishContext *context, const uint8_t *key, size_t keyLen);
void twofishDecryptBlock(TwofishContext *context, const uint8_t *input, uint8_t *output);
```
Standard Twofish decryption.

```c
uint32_t crc32(void *buffer, int len);
```
Standard ANSI CRC32 checksum (with polinominal 0xedb88320, same as in PNG and gzip).

```c
int mbedtls_md5(const unsigned char *input, size_t ilen, unsigned char output[16]);
```
Standard MD5 checksum, see [Mbed-TLS](https://github.com/Mbed-TLS/mbedtls).

```c
void mbedtls_aes_init(mbedtls_aes_context *ctx);
void mbedtls_aes_free(mbedtls_aes_context *ctx);
void mbedtls_aes_xts_init(mbedtls_aes_xts_context *ctx);
void mbedtls_aes_xts_free(mbedtls_aes_xts_context *ctx);
int mbedtls_aes_setkey_enc(mbedtls_aes_context *ctx, const unsigned char *key, unsigned int keybits);
int mbedtls_aes_setkey_dec(mbedtls_aes_context *ctx, const unsigned char *key, unsigned int keybits);
int mbedtls_aes_xts_setkey_enc(mbedtls_aes_xts_context *ctx, const unsigned char *key, unsigned int keybits);
int mbedtls_aes_xts_setkey_dec(mbedtls_aes_xts_context *ctx, const unsigned char *key, unsigned int keybits);
int mbedtls_aes_crypt_ecb(mbedtls_aes_context *ctx, int mode, const unsigned char input[16], unsigned char output[16]);
int mbedtls_aes_crypt_cbc(mbedtls_aes_context *ctx, int mode, size_t length, unsigned char iv[16],
    const unsigned char *input, unsigned char *output);
int mbedtls_aes_crypt_xts(mbedtls_aes_xts_context *ctx, int mode, size_t length, const unsigned char data_unit[16],
    const unsigned char *input, unsigned char *output);
int mbedtls_aes_crypt_cfb128(mbedtls_aes_context *ctx, int mode, size_t length, size_t *iv_off, unsigned char iv[16],
    const unsigned char *input, unsigned char *output);
int mbedtls_aes_crypt_cfb8(mbedtls_aes_context *ctx, int mode, size_t length, unsigned char iv[16],
    const unsigned char *input, unsigned char *output);
int mbedtls_aes_crypt_ofb(mbedtls_aes_context *ctx, size_t length, size_t *iv_off, unsigned char iv[16],
    const unsigned char *input, unsigned char *output);
int mbedtls_aes_crypt_ctr(mbedtls_aes_context *ctx, size_t length, size_t *nc_off,
    unsigned char nonce_counter[16], unsigned char stream_block[16],
    const unsigned char *input, unsigned char *output);
```
Standard AES decryption for XTS, ECB, CBC, CBF, OFB, CTR modes; see [Mbed-TLS](https://github.com/Mbed-TLS/mbedtls).

